package com.neusoft.bizcore.auth.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.auth.common.bean.OrgTreeBean;
import com.neusoft.bizcore.auth.common.bean.PermissionBean;
import com.neusoft.bizcore.auth.common.bean.RoleBean;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.auth.common.service.AuthUserDetailsService;
import com.neusoft.bizcore.auth.common.utils.MD5Util;
import com.neusoft.bizcore.auth.converter.AuthUserConverter;
import com.neusoft.bizcore.auth.dto.AuthUserCreateUpdateDTO;
import com.neusoft.bizcore.auth.dto.AuthUserDTO;
import com.neusoft.bizcore.auth.enums.AuthPermissionType;
import com.neusoft.bizcore.auth.model.AuthOganization;
import com.neusoft.bizcore.auth.model.AuthUser;
import com.neusoft.bizcore.auth.repository.AuthOganizationRepository;
import com.neusoft.bizcore.auth.repository.AuthUserRepository;
import com.neusoft.bizcore.auth.service.AuthOganizationService;
import com.neusoft.bizcore.auth.service.AuthUserService;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;

@Service
public class AuthUserServiceImpl implements AuthUserService, AuthUserDetailsService {

    @Autowired
    private AuthUserRepository authUserRepository;
    @Autowired
    private AuthUserConverter authUserConverter;
    @Autowired
    private AuthOganizationService authOganizationService;
    @Autowired
    private AuthOganizationRepository authOganizationRepository;

    @Override
    public List<AuthUserDTO> findAll(final Searchable searchable) {
        final List<AuthUser> models = this.authUserRepository.search(searchable);
        final List<AuthUserDTO> dtos = this.authUserConverter.toListDTO(models);
        return dtos;
    }
    
    @Override
    public List<AuthUserDTO> findUser(String orgCode) {
            // 科技中心部门可以看到下面所有二级部门的用户
            final Searchable searchable = new Searchable();
            if ("kj".equalsIgnoreCase(orgCode)) {
                final AuthOganization kjRoot = this.authOganizationRepository.findByCode("kj");
                final List<AuthOganization> subNodes = this.authOganizationRepository.findByParent(kjRoot);
                subNodes.add(kjRoot);
                final List<String> orgCodes = subNodes.stream().map(org -> org.getCode()).collect(Collectors.toList());
                searchable.put("orgCodes", orgCodes);
            }else {
            	 final List<String> orgCodes = new ArrayList<String>();
            	 orgCodes.add(orgCode);
            	searchable.put("orgCodes", orgCodes);
            }
        final List<AuthUser> models = this.authUserRepository.search(searchable);
        final List<AuthUserDTO> dtos = this.authUserConverter.toListDTO(models);
        return dtos;
    }

    @Override
    public UserBean loadUserByUsername(final String username) {
        final AuthUser model = this.authUserRepository.findByUsername(username);
        if (null == model) {
            return null;
        }

        final List<RoleBean> roles =
                model.getRoles().stream().map(it -> {
                    final PermissionBean permissions = new PermissionBean();
                    it.getPermissions().stream().forEach(p -> {
                        if (AuthPermissionType.menu.equals(p.getType())) {
                            permissions.getMenus().add(p.getCode());
                        } else if (AuthPermissionType.action.equals(p.getType())) {
                            permissions.getActions().add(p.getCode());
                        }
                    });
                    return new RoleBean(it.getCode(), permissions);
                }).collect(Collectors.toList());

        final PermissionBean permissions = new PermissionBean();
        model.getPermissions().stream().forEach(it -> {
            if (AuthPermissionType.menu.equals(it.getType())) {
                permissions.getMenus().add(it.getCode());
            } else if (AuthPermissionType.action.equals(it.getType())) {
                permissions.getActions().add(it.getCode());
            }
        });
        final Set<String> set = new HashSet<>();
        model.getOganizations().stream().forEach(it -> {
            final OrgTreeBean t = this.authOganizationService.orgTree(it.getCode());
            final List<String> flat = new ArrayList<>();
            this.iter(t, flat);
            set.addAll(flat);
        });

        final UserBean bean =
                new UserBean(model.getId(), model.getUsername(), model.getName(), model.getPassword(), roles,
                        permissions, set);
        bean.setEnabled(model.isEnabled());
        bean.setPhone(model.getPhone());
        bean.setSalt(model.getSalt());
        return bean;
    }

    private void iter(final OrgTreeBean b, final List<String> flat) {
        flat.add(b.getCode());
        if ((null == b.getChildren()) || (b.getChildren().size() == 0)) {
            return;
        }
        b.getChildren().forEach(it -> {
            this.iter(it, flat);
        });

    }

    @Override
    public Page<AuthUserDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<AuthUser> models = this.authUserRepository.search(pageable, searchable);
        return this.authUserConverter.toPageDTO(models);
    }

    @Override
    public AuthUserDTO details(final Long id) {
        AuthUser model;
        try {
            model = this.authUserRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }

        return this.authUserConverter.toDTO(model);
    }

    @Override
    public AuthUserDTO create(final AuthUserCreateUpdateDTO dto) {
        final AuthUser model = this.authUserConverter.toModel(dto);
        this.authUserRepository.save(model);
        return this.authUserConverter.toDTO(model);
    }

    @Override
    public AuthUserDTO create(final AuthUserDTO dto) {
        final AuthUser model = this.authUserConverter.toModel(dto);
        this.authUserRepository.save(model);
        return this.authUserConverter.toDTO(model);
    }

    @Override
    public AuthUserDTO update(final Long id, final AuthUserCreateUpdateDTO dto) {
        AuthUser model;
        try {
            model = this.authUserRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }

        dto.setId(model.getId());
        model = this.authUserConverter.toModel(dto);
        this.authUserRepository.save(model);
        return this.authUserConverter.toDTO(model);
    }

    @Override
    public void delete(final Long id) {
        this.authUserRepository.deleteById(id);
    }

    @Override
    public void resetPass(final long id, final String password) {
        AuthUser model;
        try {
            model = this.authUserRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }
        final String saltStr = null == model.getSalt() ? MD5Util.getSaltStr() : model.getSalt();
        final String passmd5 = MD5Util.getEncryptedPwd(password, saltStr.getBytes());

        model.setPassword(passmd5);
        model.setSalt(saltStr);
        this.authUserRepository.save(model);
    }

    @Override
    public List<AuthUserDTO> details(final List<String> usernames) {
        final List<AuthUser> mUsers = this.authUserRepository.findByUsernameIn(usernames);
        final List<AuthUserDTO> dUsers = this.authUserConverter.toListDTO(mUsers);
        return dUsers;
    }

    @Override
    public boolean checkOldPassword(final long id, final String oldPassword) {
        AuthUser model;
        try {
            model = this.authUserRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, id);
        }
        // 兼容非salt加密的原密码
        final String saltStr = null == model.getSalt() ? "" : model.getSalt();
        final String passmd5 =
                MD5Util.getEncryptedPwd(oldPassword, saltStr.getBytes());
        if (model.getPassword().equals(passmd5)) {
            return true;
        }
        return false;
    }
}
